# https://www.17k.com/all/book/2_0_0_0_0_0_0_0_3.html
import httpx, inspect, os, asyncio
import random
import string
from lib.log import DBG, INFO, ERROR, EXCEPTION


# 生成随机字符串
def random_string(length):
    letters = string.ascii_letters + string.digits  # 包含字母和数字
    return ''.join(random.choice(letters) for i in range(length))


def get_header():
    # print(f"num:{cls.VISIT_NUM}")
    headers = {
        # "Host": "www.qyhhs2.digital",
        "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:120.0) Gecko/20100101 Firefox/120.0",
        "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8",
        "Accept-Language": "zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2",
        "Accept-Encoding": "gzip, deflate, br",
        "Connection": "keep-alive",
        "Sec-Fetch-Dest": "document",
        "Sec-Fetch-Mode": "navigate",
        "Sec-Fetch-Site": "none",
        "TE": "trailers",
        "Cookie": random_string(50)
    }

    return headers


def fetch(url, stream=False, save_path=None, set_header=False):
    """
    下载URL

    :param stream: 加载结果是否是二进制文件流/文本
    :param save_path: 保存到文件
    :param url: url
    :return: 加载的文本/保存文件流的路径
    """
    # DBG(f"开始请求页面: {url}, 是否文件流:{stream}, 保存目录: {save_path}")
    with httpx.Client(verify=False) as client:
        if stream:
            chunk_size = 1024 * 1024  # 1M
            with httpx.stream(method="GET", url=url, follow_redirects=True) as response:
                with open(save_path, 'wb') as file:
                    for chunk in response.iter_bytes(chunk_size=chunk_size):
                        if chunk:
                            DBG(f"下载：{len(chunk)}")
                            file.write(chunk)
                        else:
                            DBG(f"response错误：{url}")
            return save_path

        else:
            try:
                response = client.get(url, follow_redirects=True)
                DBG(f"请求页面完成: {url}, size:{len(response.text)}")
                if save_path:
                    with open(save_path, "w") as f:
                        f.write(response.text)
                    return save_path
                else:
                    return response.text

            except httpx.RequestError as exc:
                # 处理请求错误，如网络连接问题等
                print("Request error:", exc)
                return None
            except httpx.HTTPError as exc:
                # 处理HTTP错误，如服务器返回错误状态码等
                print("HTTP error:", exc)
                return None
            except Exception as exc:
                # 处理其他异常情况
                print("Error:", exc)
                return None


async def async_fetch(url, save_type="w", save_path=None, set_header=False):
    """
    下载URL

    :param set_header:
    :param save_path: 保存到文件
    :param url: url
    :return: 加载的文本/保存文件流的路径
    """
    # DBG(f"开始请求页面: {url}, 是否文件流:{stream}, 保存目录: {save_path}")
    async with httpx.AsyncClient(verify=False, follow_redirects=True) as client:

        if save_type == "wb":
            try:
                response = await client.get(url=url)

                if response.status_code == 200:
                    with open(save_path, 'wb') as file:
                        for chunk in response.iter_bytes(chunk_size=8192):
                            if chunk:
                                file.write(chunk)
                    return save_path
                else:
                    ERROR(f"请求数据失败: {url}: {response.status_code}")
                    return None
            except httpx.RequestError as exc:
                # 处理请求错误，如网络连接问题等
                ERROR(f"Request error: {exc}")
                return None
            except httpx.HTTPError as exc:
                # 处理HTTP错误，如服务器返回错误状态码等
                ERROR(f"HTTP error: {exc}")
                return None
            except Exception as exc:
                # 处理其他异常情况
                ERROR(f"Error: {exc}")
                return None

        else:

            try:
                # DBG(f"try加载文件: {url}, save_path:{save_path}")
                try:
                    with open(save_path, "r", encoding='utf-8') as f:
                        content = f.read()
                        if len(content) > 0:
                            # DBG(f"加载数据成功: {url}, save_path:{save_path}, size:{len(content)}")
                            return content
                        else:
                            ERROR(f"加载数据为空: {url}, save_path:{save_path}, size:{len(content)}")

                except FileNotFoundError:
                    # ERROR(f"加载数据失败: {url}, save_path:{save_path}")
                    pass
                except Exception as exc:
                    ERROR(f"加载数据失败: {url}, save_path:{save_path}")

                if set_header:
                    header = get_header()
                    response = await client.get(url=url)
                else:
                    response = await client.get(url=url)
                if response.status_code == 200:
                    DBG(f"请求数据成功: {url}, size:{len(response.text)}")
                    # DBG(response.text)
                    if save_path:
                        with open(save_path, "w", encoding='utf-8') as f:
                            f.write(response.text)
                    return response.text
                elif response.status_code == 301:
                    redirect_url = response.headers.get('Location')
                    ERROR(f"请求数据重定向: {url}-->{redirect_url}")
                else:
                    ERROR(f"请求数据失败: {url}: {response.status_code}")
                    return None

            except httpx.RequestError as exc:
                # 处理请求错误，如网络连接问题等
                ERROR(f"Request error: {exc}, {url}")
                return None
            except httpx.HTTPError as exc:
                # 处理HTTP错误，如服务器返回错误状态码等
                ERROR(f"HTTP error: {exc}, {url}")
                return None
            except Exception as exc:
                # 处理其他异常情况
                ERROR(f"Error: {exc}, {url}")
                return None


# Python 3.7+
if __name__ == "__main__":
    pass
    # result = do_fetch(url="https://www.hs35n.xyz/vodtypehtml/1.html")

    # asyncio.run(async_fetch(
    #     url="http://down.echo188.com:81/dngs/windows_10_professional_x64_2023.iso",
    #     stream=True,
    #     save_path="windows_10_professional_x64_2023.iso"
    # ))

    # asyncio.run(async_fetch(
    #     url="https://www.hs35o.xyz/vodtypehtml/1-22.html",
    #     stream=False,
    #     save_path=None
    # ))
